#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>
#include "matrix.hpp"
#include "vector.hpp"
#include <map>

#include <iostream>
#include <list>
#include <cmath>
#include <regex>
#include <complex>
#include <appendix/point.h>
#include <parsers/parsers.hpp>

namespace sol {
   template <>
   struct is_automagical<std::vector<std::complex<double> > > : std::false_type {};
   template <>
   struct is_container<std::vector<std::complex<double> > > : std::true_type {};
   template <>
   struct is_to_stringable<std::vector<std::complex<double> > > : std::true_type {};
//   template <>
//   struct is_to_stringable<my_type> : std::false_type {};

   template <>
   struct is_automagical<std::vector<Point3Dd > > : std::false_type {};

  // template <>
  // struct is_automagical<std::vector< std::vector<double> > > : std::false_type {};
   //template <>
   //struct is_container<std::vector<Point3Dd > > : std::true_type {};
   ////template <>
   //struct is_to_stringable<std::vector<Point3Dd > > : std::true_type {};
}





namespace LuaNumeric {
	typedef std::map<std::string,std::string> ssmap;


	template<class T>
	sol::object getter(const std::map<std::string,T>& vec, sol::stack_object key, sol::this_state L) {
			// we use stack_object for the arguments because we know
			// the values from Lua will remain on Lua's stack,
			// so long we we don't mess with it
			// String keys failed, check for numbers
			auto maybe_numeric_key = key.as<sol::optional<std::string>>();
			if (maybe_numeric_key) {
				std::string mk = *maybe_numeric_key;
				auto iter = vec.find(mk);
				if( iter !=vec.end())
					return sol::object(L, sol::in_place, *iter );
			}
			// No valid key: push nil
			// Note that the example above is a bit unnecessary:
			// binding the variables x and y to the usertype
			// would work just as well and we would not
			// need to look it up here,
			// but this is to show it works regardless
			return sol::object(L, sol::in_place, sol::lua_nil);
	}
	template<class T>
	void setter(std::map<std::string,T>& vec, const std::string& idx, const T& val) {
		vec[idx] = val;
	}

	void open_luaMap(sol::table& module) {

		module.set_function("new_ssmap", sol::overload(
											[]() { return std::make_shared<ssmap>(); }

							)
		);

		module.new_usertype<ssmap>("ssmap"
				,"clear", ( void (ssmap::*)(void)) & ssmap::clear
				,"size",[](ssmap* m){
						return (int) m->size();
				}
				,"insert",[](ssmap* m,const std::string& k,const std::string& v){
						m->insert( std::make_pair(k,v) );
				}
				,sol::meta_function::index, &getter<std::string>
				,sol::meta_function::new_index, &setter<std::string>
				,sol::meta_function::length, ( size_t (ssmap::*)(void)) & ssmap::size
		);
	}



} // namespace my_object

// automatically bound to tostring(obj) [ __tostring ]

